#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <strings.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

# define SERV_PORT 9527

//多进程服务器
void sys_err(const char *str)
{
	perror(str);
	exit(1);
}

void catch_child(int signum)//回收子进程函数
{
	while(waitpid(0, NULL, WNOHANG) > 0);//waitpid只回收一个进程，所以要在此循环
	return ;
}

int main(int argc, char *argv[])
{
	int lfd = 0, cfd = 0; //lfd接收socket创建的文件描述符,cfd接受accept创建的与客户端通信的文件描述符
	int fret,i;//接受read返回，read函数返回读到的字节数
	pid_t pid;//子进程id
	char buf[4096], clit_ip[1024];

	struct sockaddr_in	serv_addr, clit_addr;
	socklen_t	clit_addr_len;

	bzero(&serv_addr, sizeof(serv_addr));//将地址空间清零，即初始化，也可以用memset函数
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(SERV_PORT);//本地字节序转网络字节序
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);//任意可用ip地址

	lfd = socket(AF_INET,SOCK_STREAM,0);
	if(lfd == -1){
		sys_err("server socket create error");
	}

	int ret = bind(lfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
	if(ret == -1){
		sys_err("server bind error");
	}

	ret = listen(lfd, 128);
	if(ret == -1){
		sys_err("server listen error");
	}
	
	//上面是监听socket

	clit_addr_len = sizeof(clit_addr);//传入只用求一次，放在循环里会反复求
	while(1){

		cfd = accept(lfd, (struct sockaddr *)&clit_addr, &clit_addr_len);
		if(cfd == -1){
			sys_err("serveraccept error");
		}
		printf("client ip:%s, port:%d\n", 
				inet_ntop(AF_INET, &clit_addr.sin_addr.s_addr, clit_ip, sizeof(clit_ip)),
				ntohs(clit_addr.sin_port));

		pid = fork();//创建子进程

		if (pid < 0) {
			sys_err("fork error");
		}
		else if (pid == 0) { //子进程
			close(lfd);//因为fork会复制所以东西，所以父子进程都有lfd、cfd,子进程不需要监听客户端，所以关闭lfd

			while(1){
				fret = read(cfd,buf,sizeof(buf));
				if (fret == 0){
					printf("client %d closed", cfd);
					break;
				}

				write(STDOUT_FILENO, buf ,fret);

				for(i=0; i<fret; i++){
					buf[i] = toupper(buf[i]);//对数据进行操作
				}

				write(cfd, buf,fret);
			}

			close(cfd);
		}
		else { //父进程
			struct sigaction act;

			act.sa_handler = catch_child;
			sigemptyset(&act.sa_mask);
			act.sa_flags = 0;

			ret = sigaction(SIGCHLD, &act, NULL );//注册信号
			if (ret == -1){
				sys_err("sigaction error");
			}
			close(cfd);
			continue;//回去继续等待其他客户端连接	
		}
	}

	return 0;
}

